//
// Created by HP on 2025/11/19.
//

#include "../include/Headler.h"
#include "../model/Stations.h"
#include "../model/Ticket.h"
#include "../model/StationTrain.h"
#include "../model/Travel.h"

/**
 * 获取所有站点名称的接口函数
 * @param req 请求对象，包含客户端请求信息
 * @param res 响应对象，用于返回处理结果给客户端
 * 从数据库查询所有站点名称，并返回给客户端
 */
void getStations(const Request& req, Response& res) {
    // 构建SQL查询语句，查询所有站点名称并按升序排序
    std::string querySql = "SELECT DISTINCT name, role FROM stations ORDER BY name ASC;";
    // 执行数据库查询
    auto result = DBConnector::getInstance()->query(querySql);

    // 创建用于存储响应数据的映射容器
    std::map<std::string ,JsonValue> resMp;

    // 如果查询结果为空，直接返回空的成功响应
    if (result.empty()) {
        res.success(resMp);
    }

    // 创建用于存储站点名称的向量容器
    std::vector<std::map<std::string,std::string> > stations;

    // 遍历查询结果，将所有站点名称添加到向量中
    for (auto &row : result) {
        stations.push_back({
            {"name",row["name"]},
            {"type",row["role"]}
        });
    }

    // 将站点名称列表和总数添加到响应数据中
    resMp["data"] = JsonValue(stations);
    resMp["total"] = JsonValue((int)stations.size());

    // 返回成功响应
    res.success(resMp);
}

/**
 * 获取站点数量的处理函数
 * @param req HTTP请求对象
 * @param res HTTP响应对象
 * 该函数查询数据库中不重复的站点名称数量，并将结果返回给客户端
 */
void getStationCnts(const Request& req, Response& res) {
    std::string querySql = "SELECT COUNT(DISTINCT name) AS total FROM stations;";
    // 构建SQL查询语句，统计stations表中不重复的name数量，并将结果列命名为total

    auto result = DBConnector::getInstance()->query(querySql);
    // 通过数据库连接器单例执行查询

    std::map<std::string ,JsonValue> resMp;
    // 创建用于存储响应数据的map
    if (result.empty()) {
    // 检查查询结果是否为空
        res.success(resMp);
        // 如果结果为空，返回空的响应数据
    }

    resMp["data"] = JsonValue(result[0]["total"]);
    // 将查询结果中的total值存入响应map

    res.success(resMp);
    // 返回成功响应，包含查询到的站点数量
}

/**
 * 获取城市列表的函数处理程序
 * 该函数从数据库中查询所有不重复的城市名称，并按升序排序后返回
 * @param req HTTP请求对象，包含客户端请求信息
 * @param res HTTP响应对象，用于返回处理结果
 */
void getCities(const Request& req, Response& res) {
    // 定义SQL查询语句，用于获取不重复的城市名称并按升序排序
    std::string querySql = "SELECT DISTINCT city FROM stations ORDER BY city ASC;";
    // 执行SQL查询，获取结果集
    auto result = DBConnector::getInstance()->query(querySql);

    // 创建一个用于存储响应数据的map
    std::map<std::string ,JsonValue> resMp;

    // 检查查询结果是否为空
    if (result.empty()) {
        // 如果结果为空，返回空的响应数据
        res.success(resMp);
    }

    // 创建一个vector用于存储城市名称
    std::vector<std::string > stations;

    // 遍历查询结果，将每个城市名称添加到vector中
    for (auto &row : result) {
        stations.push_back(row["city"]);
    }

    // 将城市列表数据添加到响应map中
    resMp["data"] = JsonValue(stations);
    // 将城市总数添加到响应map中
    resMp["total"] = JsonValue((int)stations.size());

    // 返回成功响应
    res.success(resMp);
}

/**
 * 获取城市数量的函数
 * 该函数从数据库中查询不同城市的总数，并将结果以JSON格式返回
 *
 * @param req HTTP请求对象，包含请求信息
 * @param res HTTP响应对象，用于返回处理结果
 */
void getCitiesCnts(const Request& req, Response& res) {
    // 定义SQL查询语句，计算stations表中不同城市的总数
    std::string querySql = "SELECT COUNT(DISTINCT city) AS total FROM stations;";

    // 通过数据库连接器执行查询，获取结果
    auto result = DBConnector::getInstance()->query(querySql);

    // 创建用于存储响应数据的map
    std::map<std::string ,JsonValue> resMp;
    // 检查查询结果是否为空
    if (result.empty()) {
        // 如果结果为空，返回空的响应数据
        res.success(resMp);
    }

    // 将查询结果中的total字段值存入响应map
    resMp["data"] = JsonValue(result[0]["total"]);

    // 返回成功响应，包含数据
    res.success(resMp);
}


/**
 * @brief 获取票务列表（支持分页）
 *
 * @param req 请求对象，包含查询参数：
 *            - TrainNumber: 列车号
 *            - PassingStation: 途径车站（按顺序排列，','分隔）
 *            - StationArriveTime: 到达各个车站时间（按车站顺序，‘,'分隔，"YYYY-MM-DD HH:MM::SS" 格式）
 *            - StationStartTime: 出发各个车站时间（按车站顺序，‘,'分隔，"YYYY-MM-DD HH:MM::SS" 格式）
 *            - TrainType: 车类型
 *            - TrainSeat: 车座位数（按价值从高到低排列，','分隔）
 *            - Prices: 价格
 *            - Company: 由那家铁路局负责
 * @param res 响应对象，返回JSON格式：
 *            - message: 状态消息
 *            - status: 状态码
 */
void addTicketsByTrain(const Request& req, Response& res) {
    std::string trainNumber = req.query_param("TrainNumber");
    std::vector<std::string> passingStations = split(req.query_param("PassingStation"), ',');
    std::vector<std::string> stationStartTimes = split(req.query_param("StationStartTime"), ',');
    std::vector<std::string> stationArriveTimes = split(req.query_param("StationArriveTime"), ',');
    std::vector<std::string> prices = split(req.query_param("Prices"), ',');
    std::string trainType = req.query_param("TrainType");
    std::string trainSeat = req.query_param("TrainSeat");
    std::string company = req.query_param("Company");

    int trainId = Train::getIdFromKey("name", trainNumber);
    if (trainId == 0) {
        Train train;
        train.name = trainNumber;
        train.type = trainType;
        train.company = company;
        train.save();

        trainId = Train::getIdFromKey("name", trainNumber);
    }

    if (passingStations.size() != stationArriveTimes.size() || passingStations.size() != prices.size() || passingStations.size() != stationStartTimes.size()) {
        res.error(400, "Invalid parameters");
        return;
    }

    std::vector<int> stationsId;
    for (const auto& stationName : passingStations) {
        int stationId = Station::getIdFromKey("name", stationName);
        if (stationId == 0) {
            Station station;
            station.name = stationName;
            station.city = stationName.substr(0, fmin(stationName.size(), 2));
            station.role = StationRole::TrainStation;        // 默认设为火车站
            station.save();

            stationId = Station::getIdFromKey("name", stationName);
        }
        stationsId.push_back(stationId);
    }

    // 分割票种算法

    int seats;
    try {
        seats = std::stoi(trainSeat);
    } catch (const std::exception& e) {
        res.error(400, "Invalid trainSeat parameter");
        return;
    }

    int n=passingStations.size();
    if (n<2) {
        res.error(400, "Invalid PassingStation parameter");
        return;
    }

    for (int i=0;i<n;i++) {
        if (stationArriveTimes[i] >= stationStartTimes[i]) {
            res.error(400, "Invalid StationArriveTime parameter");
        }

        StationTrain stationTrain;
        stationTrain.station_id = std::to_string(stationsId[i]);
        stationTrain.train_id = std::to_string(trainId);
        stationTrain.station_order = std::to_string(i);
        stationTrain.arrival_time = stationArriveTimes[i];
        stationTrain.departure_time = stationStartTimes[i];
        stationTrain.stop_duration = "00:00:00";
        stationTrain.save();
    }

    if (seats < 800) {
        res.error(400, "Invalid trainSeat parameter");
        return;
    }

    // 分票逻辑，首尾站预分配40，剩余按照比例下降，最少不低于1
    if (trainType==TrainType::HighSpeed) {
        int firstClassCnt = seats / 4;
        int secondClassCnt = seats - firstClassCnt;

        double averageTicket = 1.0 / (n-1);

        for (int i=0;i<n-1;i++) {
            for (int j=i+1;j<n;j++) {
                int len=j-i;
                double rate = averageTicket / (n-len);
                int firstCnt =  firstClassCnt * rate;
                int secondCnt = secondClassCnt * rate;
                Ticket ticket;
                ticket.trainId = std::to_string(trainId);
                ticket.from = passingStations[i];
                ticket.to = passingStations[j];
                ticket.cnt = firstCnt;
                ticket.price = std::to_string((stoi(prices[j])-stoi(prices[i])) * 2);
                ticket.startTime = stationStartTimes[i];
                ticket.endTime = stationArriveTimes[j];
                ticket.type = TypeOfTicket::HIGHSPEEDTRAINFirstClass;
                ticket.save();

                ticket.trainId = std::to_string(trainId);
                ticket.from = passingStations[i];
                ticket.to = passingStations[j];
                ticket.cnt = secondCnt;
                ticket.price = std::to_string((stoi(prices[j])-stoi(prices[i])));
                ticket.startTime = stationStartTimes[i];
                ticket.endTime = stationArriveTimes[j];
                ticket.type = TypeOfTicket::HIGHSPEEDTRAINSecondClass;
                ticket.save();
            }
        }
    } else if (trainType==TrainType::BulletTrain) {
        int firstClassCnt = seats / 4;
        int secondClassCnt = seats - firstClassCnt;

        double averageTicket = 1.0 / (n-1);

        for (int i=0;i<n-1;i++) {
            for (int j=i+1;j<n;j++) {
                int len=j-i;
                double rate = averageTicket / (n-len);
                int firstCnt =  firstClassCnt * rate;
                int secondCnt = secondClassCnt * rate;
                Ticket ticket;
                ticket.trainId = std::to_string(trainId);
                ticket.from = passingStations[i];
                ticket.to = passingStations[j];
                ticket.cnt = firstCnt;
                ticket.price = std::to_string((stoi(prices[j])-stoi(prices[i])) * 2);
                ticket.startTime = stationStartTimes[i];
                ticket.endTime = stationArriveTimes[j];
                ticket.type = TypeOfTicket::QUICKSPEEDTRAINFirstClass;
                ticket.save();

                ticket.trainId = std::to_string(trainId);
                ticket.from = passingStations[i];
                ticket.to = passingStations[j];
                ticket.cnt = secondCnt;
                ticket.price = std::to_string((stoi(prices[j])-stoi(prices[i])));
                ticket.startTime = stationStartTimes[i];
                ticket.endTime = stationArriveTimes[j];
                ticket.type = TypeOfTicket::QUICKSPEEDTRAINSecondClass;
                ticket.save();
            }
        }
    } else if (trainType==TrainType::OrdinaryTrain) {
        int softBed = seats / 10;
        int hardBed = seats / 8;
        int softSeat = seats / 4;
        int hardSeat = seats - softBed - hardBed - softSeat;

        double averageTicket = 1.0 / (n-1);

        for (int i=0;i<n-1;i++) {
            for (int j=i+1;j<n;j++) {
                int len=j-i;
                double rate = averageTicket / (n-len);
                int softBedCnt =  softBed * rate;
                int hardBedCnt = hardBed * rate;
                int softSeatCnt = softSeat * rate;
                int hardSeatCnt = hardSeat * rate;
                Ticket ticket;
                ticket.trainId = std::to_string(trainId);
                ticket.from = passingStations[i];
                ticket.to = passingStations[j];
                ticket.cnt = softBedCnt;
                ticket.price = std::to_string((stoi(prices[j])-stoi(prices[i])) * 4);
                ticket.startTime = stationStartTimes[i];
                ticket.endTime = stationArriveTimes[j];
                ticket.type = TypeOfTicket::NORMALLQUICKTRAINSoftBed;
                ticket.save();

                ticket.trainId = std::to_string(trainId);
                ticket.from = passingStations[i];
                ticket.to = passingStations[j];
                ticket.cnt = hardBedCnt;
                ticket.price = std::to_string((stoi(prices[j])-stoi(prices[i]))*3);
                ticket.startTime = stationStartTimes[i];
                ticket.endTime = stationArriveTimes[j];
                ticket.type = TypeOfTicket::NORMALLQUICKTRAINHardBed;
                ticket.save();

                ticket.trainId = std::to_string(trainId);
                ticket.from = passingStations[i];
                ticket.to = passingStations[j];
                ticket.cnt = softSeatCnt;
                ticket.price = std::to_string((stoi(prices[j])-stoi(prices[i]))*2);
                ticket.startTime = stationStartTimes[i];
                ticket.endTime = stationArriveTimes[j];
                ticket.type = TypeOfTicket::NORMALLQUICKTRAINSoftSeat;
                ticket.save();

                ticket.trainId = std::to_string(trainId);
                ticket.from = passingStations[i];
                ticket.to = passingStations[j];
                ticket.cnt = hardSeatCnt;
                ticket.price = std::to_string((stoi(prices[j])-stoi(prices[i])));
                ticket.startTime = stationStartTimes[i];
                ticket.endTime = stationArriveTimes[j];
                ticket.type = TypeOfTicket::NORMALLQUICKTRAINHardSeat;
                ticket.save();
            }
        }
    }

    res.success();
}